﻿using System;
using System.Collections.Generic;


namespace JAAF.UI
{
    /// <summary>
    /// Represents the state owned by a user interface process.
    /// </summary>
    public class UIProcessState : IList<object>
    {
        #region Instance Data

        private List<StateElement> m_lstElements;
        private Dictionary<string, int> m_dicKeyIndexes;

        /// <summary>
        /// The <see cref="UIProcess"/> that owns this state.
        /// </summary>
        private UIProcess m_oOwningProcess;

        #endregion


        #region Initialization

        /// <summary>
        /// Creates a new instance of the UIProcessState type.
        /// </summary>
        /// <param name="_colCombineWithState"></param>
        internal UIProcessState(UIProcess _oOwningProcess, UIProcessState _colCombineWithState = null)
        {
            m_lstElements = new List<StateElement>();
            m_dicKeyIndexes = new Dictionary<string, int>(); //new Dictionary<string, int>(CaseInsensitiveEqualityComparer.Default); TODO: Implement case insensitive comparer
            m_oOwningProcess = _oOwningProcess;

            if (_colCombineWithState != null)
                this.Combine(_colCombineWithState);
        }

        #endregion


        #region Additional Methods

        /// <summary>
        /// Adds a new <see cref="StateElement">element</see> into the
        /// state collection.
        /// </summary>
        /// <param name="_sElementName">The name by which this element is identified.</param>
        /// <param name="_oValue">The value of the element.</param>
        /// <param name="_eScope">The <see cref="StateElementScopeEnum">scope</see>
        /// of this element.</param>
        /// <param name="_eAccessLevel">The access level ava.</param>
        public void Add(string _sElementName, object _oValue, 
                        StateElementScopeEnum _eScope = StateElementScopeEnum.Private,
                        StateElementAccessLevelEnum _eAccessLevel = StateElementAccessLevelEnum.Full)
        {
            StateElement oElm = new StateElement(_sElementName, _oValue, _eScope, _eAccessLevel);
            m_dicKeyIndexes.Add(_sElementName, m_lstElements.Count);
            m_lstElements.Add(oElm);

            try
            {
                if (m_oOwningProcess != null)
                    m_oOwningProcess.OnStateChangedTrigger(oElm.Name, null);
            }
            catch
            { }
        }

        public void Remove(string _sName)
        {
            this.RemoveAt(m_dicKeyIndexes[_sName]);
        }

        public bool ContainsKey(string _sName)
        {
            return m_dicKeyIndexes.ContainsKey(_sName);
        }

        public object this[string _sName]
        {
            get
            {
                int ixElement;

                if (m_dicKeyIndexes.TryGetValue(_sName, out ixElement))
                    return m_lstElements[ixElement].Value;
                else
                {
                    this.Add(_sName, null);
                    return null;
                }
            }

            set
            {
                int ixElement;

                if (m_dicKeyIndexes.TryGetValue(_sName, out ixElement))
                    this[ixElement] = value;
                else
                    this.Add(_sName, value);
            }
        }

        /// <summary>
        /// Appends the elements of the <paramref name="_colSourceState"/> at
        /// the end of this collection.
        /// </summary>
        /// <param name="_colSourceState">The <see cref="UIProcessState"/> whose
        /// elements will be appended.</param>
        public void Combine(UIProcessState _colSourceState)
        {
            foreach (StateElement oElm in _colSourceState.m_lstElements)
            {
                if (oElm.Scope == StateElementScopeEnum.Copied)
                    this.Add(oElm.Name, oElm.Value, oElm.Scope);
                else if (oElm.Scope == StateElementScopeEnum.Shared)
                {
                    m_dicKeyIndexes.Add(oElm.Name, m_lstElements.Count);
                    m_lstElements.Add(oElm);
                    oElm.ElementChanged += this.OnGlobalElementChanged;
                }
            }
        }

        #endregion

        #region IList<object> Members

        public int IndexOf(object item)
        {
            throw new NotSupportedException("Cannot lookup the index of values in a UIProcessState collection.");
        }

        void IList<object>.Insert(int _iIndex, object _oItem)
        {
            throw new NotSupportedException();
        }

        public void RemoveAt(int index)
        {
            StateElement oElm = m_lstElements[index];
            m_lstElements.RemoveAt(index);
            m_dicKeyIndexes.Remove(oElm.Name);
        }

        public object this[int index]
        {
            get
            {
                return m_lstElements[index].Value;
            }

            set
            {
                StateElement oElm = m_lstElements[index];

                object oOldValue = oElm.Value;
                oElm.Value = value;

                try
                {
                    if (m_oOwningProcess != null)
                        m_oOwningProcess.OnStateChanged(oElm.Name, oOldValue);
                }
                catch { }
            }
        }

        #endregion

        #region ICollection<object> Members

        void ICollection<object>.Add(object item)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        bool ICollection<object>.Contains(object item)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void CopyTo(object[] array, int arrayIndex)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        bool ICollection<object>.Remove(object item)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion

        #region IEnumerable<object> Members

        IEnumerator<object> IEnumerable<object>.GetEnumerator()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion

        #region ICollection<object> Members


        public void Clear()
        {
            m_lstElements.Clear();
            m_dicKeyIndexes.Clear();
        }

        public int Count
        {
            get { return m_lstElements.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        #endregion

        #region IEnumerable Members

        public System.Collections.IEnumerator GetEnumerator()
        {
            return m_lstElements.GetEnumerator();
        }

        #endregion

        #region Helper Functions

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_sName"></param>
        /// <param name="_oOldValue"></param>
        /// <param name="_oNewValue"></param>
        private void OnGlobalElementChanged(StateElement _oElement, object _oOldValue)
        {
            try
            {
                if (m_oOwningProcess != null)
                    m_oOwningProcess.OnStateChangedTrigger(_oElement.Name, _oOldValue);
            }
            catch { }
        }

        #endregion
    }
}